home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 2 / Apprentice-Release2.iso / Source Code / C / Libraries / stdwin / Ports / alfa / timer.c < prev    next >
Encoding:
C/C++ Source or Header  |  1990-10-18  |  4.3 KB  |  198 lines  |  [TEXT/????]

  1. /* TERMCAP STDWIN -- Alarm timers (BSD-specific) */
  2.  
  3. #include "alfa.h"
  4.  
  5. #include <errno.h>
  6. #include <sys/time.h>
  7.  
  8. #ifdef AMOEBA
  9. #define select(a, b, c, d, e) (-1) /* XXX just to get it to link... */
  10. #endif
  11.  
  12. /* Alarm timer values must be stored as absolute times,
  13.    but since they are in tenths of a second and stored in a long,
  14.    there isn't enough space to store the true absolute time.
  15.    Therefore, they are stored relative to the second when the
  16.    first call to wsettimer was made, which is saved in torigin */
  17.  
  18. static long torigin;        /* Seconds */
  19. static long nexttimer;        /* Deciseconds */
  20.  
  21. /* Return the window with the first timer to go off, if any, NULL otherwise */
  22.  
  23. static WINDOW *
  24. getnexttimer()
  25. {
  26.     WINDOW *win;
  27.     WINDOW *cand= NULL;
  28.     
  29.     for (win= &winlist[0]; win < &winlist[MAXWINDOWS]; ++win) {
  30.         if (win->open) {
  31.             long t= win->timer;
  32.             if (t != 0) {
  33.                 if (cand == NULL || t < cand->timer)
  34.                     cand= win;
  35.             }
  36.         }
  37.     }
  38.     return cand;
  39. }
  40.  
  41. /* Compute a new value for nexttimer.
  42.    Return the relevant window as a convenience. */
  43.  
  44. static WINDOW *
  45. setnexttimer()
  46. {
  47.     WINDOW *win= getnexttimer();
  48.     
  49.     if (win == NULL)
  50.         nexttimer= 0;
  51.     else
  52.         nexttimer= win->timer;
  53.     return win;
  54. }
  55.  
  56. /* Set the alarm timer for a given window */
  57.  
  58. void
  59. wsettimer(win, deciseconds)
  60.     WINDOW *win;
  61.     int deciseconds;
  62. {
  63.     win->timer= 0;
  64.     if (deciseconds > 0) {
  65.         struct timeval tv;
  66.         struct timezone tz;
  67.         
  68.         if (gettimeofday(&tv, &tz) >= 0) {
  69.             if (torigin == 0) {
  70.                 torigin= tv.tv_sec;
  71.             }
  72.             win->timer= deciseconds + 10 * (tv.tv_sec - torigin) +
  73.                 tv.tv_usec/100000;
  74.         }
  75.     }
  76.     (void) setnexttimer();
  77. }
  78.  
  79. /* Return a pointer suitable as timeout parameter for BSD select(2).
  80.    If no alarms are currently set, return a NULL pointer. */
  81.  
  82. static struct timeval *
  83. timeout()
  84. {
  85.     if (nexttimer == 0) {
  86.         return NULL;
  87.     }
  88.     else {
  89.         static struct timeval tv;
  90.         struct timezone tz;
  91.         
  92.         if (gettimeofday(&tv, &tz) < 0) {
  93.             return NULL;
  94.         }
  95.         else {
  96.             long tout;
  97.             tout= nexttimer
  98.                 - (tv.tv_sec - torigin) * 10
  99.                 - tv.tv_usec / 100000;
  100.             if (tout <= 0)
  101.                 tv.tv_sec= tv.tv_usec= 0;
  102.             else {
  103.                 tv.tv_sec= tout / 10; 
  104.                 tv.tv_usec= (tout % 10) * 100000;
  105.             }
  106.             return &tv;
  107.         }
  108.     }
  109. }
  110.  
  111. /* Check if an alarm has gone off, and if so, generate an appropriate event.
  112.    This can be called at any time, but for efficiency reasons it should
  113.    only be called when an alarm has actually gone of (i.e., select has
  114.    timed out).  If an alarm has gone off, it will always be found by
  115.    this function. */
  116.  
  117. static bool
  118. dotimer(ep)
  119.     EVENT *ep;
  120. {
  121.     WINDOW *win= setnexttimer();
  122.     struct timeval *tp;
  123.     
  124.     if (win == NULL) {
  125.         /* no event found (spurious call) */
  126.         return FALSE;
  127.     }
  128.     tp= timeout();
  129.     if (tp == NULL) {
  130.         /* unexpected NULL timeout() */
  131.         return FALSE;
  132.     }
  133.     if (tp->tv_sec == 0 && tp->tv_usec == 0) {
  134.         /* report timer event */
  135.         ep->type= WE_TIMER;
  136.         ep->window= win;
  137.         win->timer= 0;
  138.         (void) setnexttimer();
  139.         return TRUE;
  140.     }
  141.     else {
  142.         /* it is not yet time */
  143.         return FALSE;
  144.     }
  145. }
  146.  
  147. /* Check for timer events.
  148.    Call this after trmavail() returns 0, just before calling trminput() */
  149.  
  150. bool
  151. _w_checktimer(ep, mayblock)
  152.     EVENT *ep;
  153.     bool mayblock;
  154. {
  155.     for (;;) {
  156.         struct timeval *tp= timeout();
  157.         /* This is naive.  BSD 4.3 really uses arrays of longs
  158.            as arguments to select.  Fortunately, stdin is fd 0. */
  159.         unsigned long rd, wd, xd;
  160.         int fd, nfd;
  161.         int nfound;
  162.         if (!mayblock) {
  163.             return tp != NULL &&
  164.                 tp->tv_sec == 0 && tp->tv_usec == 0 &&
  165.                 dotimer(ep);
  166.         }
  167.         fd= 0; /* stdin */
  168.         rd= 1 << fd;
  169.         nfd= fd+1;
  170.         wd= xd= 0;
  171.         errno= 0;
  172.         nfound= select(nfd, &rd, &wd, &xd, tp);
  173.         /* Note: if select returns negative, we also break
  174.            out of the loop -- better drop a timer event than
  175.            loop forever on a select error.
  176.            The only exception is EINTR, which may have been caused
  177.            by an application's signal handler */
  178.         if (nfound < 0) {
  179.             if (errno == EINTR) {
  180.                 continue;
  181.             }
  182.         }
  183.         if (nfound != 0)
  184.             break;
  185.         if (dotimer(ep))
  186.             return TRUE;
  187.     }
  188.     return FALSE;
  189. }
  190.  
  191. /* P.S.: It is not necessary to recompute nextalarm when windows are
  192.    deleted.  This can at most cause a spurious time-out, after which
  193.    dotimeout() is called again which recomputes nextalarm as a side
  194.    effect (twice, even).  Applications incur a slight overhead if they
  195.    delete a window with a timer set and no other windows have timers
  196.    set; in this case a larger part of the timeout code is called until
  197.    the alarm goes off (which is then ignored!). */
  198.